﻿using LettuceEncrypt.Acme;
using Microsoft.Extensions.Logging;

namespace LettuceEncrypt.Extensions.AliDns;

public sealed class AliDns01ChallengeProvider : IDnsChallengeProvider
{
    private readonly AlibabaCloudDnsClient _dnsClient;
    private readonly ILogger _logger;

    public AliDns01ChallengeProvider(AlibabaCloudDnsClient dnsClient, ILogger<AliDns01ChallengeProvider> logger)
    {
        _dnsClient = dnsClient;
        _logger = logger;
    }

    public async Task<DnsTxtRecordContext> AddTxtRecordAsync(string domainName, string txt, CancellationToken ct = default)
    {
        var (rr, rootDomainName) = SplitDomainName(domainName);

        _logger.LogDebug("[AliDns] Dns01 Challenge: {DomainName}. RootDomain:{domain}, Record value:{rr}", domainName, rootDomainName, rr);

        var recordId = await _dnsClient.AddDomainRecordAsync(rootDomainName, rr, "TXT", txt, ct);

        if (recordId is null)
        {
            throw new InvalidOperationException("Create Domain Record Failed");
        }

        return new DnsTxtRecordContext(domainName, recordId);
    }

    public async Task RemoveTxtRecordAsync(DnsTxtRecordContext context, CancellationToken ct = default)
    {
        var recordId = context.Txt;

        if (recordId == null)
        {
            throw new InvalidOperationException($"Cannot found record id for domain:'{context.DomainName}' type:'TXT'");
        }

        var deletedRecordId = await _dnsClient.DeleteDomainRecordAsync(recordId, ct);

        if (deletedRecordId != null)
        {
            _logger.LogInformation("DomainRecord deleted. domain:{Domain}, type:{DomainRecordType}, recordId:{RecordId}", context.DomainName, "TXT", deletedRecordId);
        }
    }

    private (string rr, string rootDomainName) SplitDomainName(string domainName)
    {
        var spans = domainName.Split('.').AsSpan<string>();

        var index = spans.Length - 2;

        var rr = string.Join(".", spans[..index]!);
        var domain = string.Join(".", spans[index..]!);

        return (rr, domain);
    }
}
